﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace FirstFloor.Documents.Pdf.ColorSpaces
{
    /// <summary>
    /// Represents the base class for all color spaces.
    /// </summary>
    internal abstract class ColorSpace
    {
        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name { get; protected set; }
        /// <summary>
        /// Gets or sets the components of the default color.
        /// </summary>
        /// <value>The default color.</value>
        public double[] DefaultColor { get; protected set; }
        /// <summary>
        /// Converts specified value to the XYZ color space.
        /// </summary>
        /// <param name="values">The values.</param>
        /// <returns></returns>
        public abstract ColorPoint ToXYZ(double[] values);
        /// <summary>
        /// Converts a value from the XYZ color space to a value in this color space.
        /// </summary>
        /// <param name="value">The value.</param>
        /// <returns></returns>
        public virtual double[] FromXYZ(ColorPoint value)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Creates the specified color space using given page context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        public static ColorSpace CreateColorSpace(PageParserContext context, string name)
        {
            if (name == "DeviceGray") {
                return DeviceGray.Default;
            }
            if (name == "DeviceRGB") {
                return DeviceRGB.Default;
            }
            if (name == "DeviceCMYK") {
                return DeviceCMYK.Default;
            }
            if (name == "Pattern") {
                return new Pattern();
            }

            var colorSpaces = context.Resources.Get<DictionaryObject>("ColorSpace");
            var colorSpace = colorSpaces.Get<ArrayObject>(name);
            name = colorSpace.Get<string>(0);

            if (name == "ICCBased") {
                // always use alternate color space
                var profile = colorSpace.Get<DictionaryObject>(1);
                return CreateICCBasedColorSpace(profile);
            }
            if (name == "Separation") {
                ColorSpace result = null;

                var alternateName = colorSpace[2] as string;
                if (alternateName == null) {
                    var alternate = (ArrayObject)colorSpace[2];
                    alternateName = (string)alternate[0];

                    if (alternateName == "ICCBased") {
                        result = CreateICCBasedColorSpace((DictionaryObject)alternate[1]);
                    }
                }
                if (result == null) {
                    result = CreateColorSpace(context, alternateName);
                }

                var dictionary = colorSpace.Get<DictionaryObject>(3);
                var function = context.Parser.GetFunction(dictionary);

                return new Separation(result, function);
            }

            throw new NotSupportedException(string.Format("Color space '{0}' is not supported", name));
        }

        private static ColorSpace CreateICCBasedColorSpace(DictionaryObject profile)
        {
            var n = profile.Get<int>("N");

            if (n == 1) { return DeviceGray.Default; }
            if (n == 3) { return DeviceRGB.Default; }
            if (n == 4) { return DeviceCMYK.Default; }

            throw new NotSupportedException(string.Format("ICCBased color space with N={0} is not supported", n));
        }
    }
}
